package cn.jingyuan.swan.uaa.web.config;

import cn.jingyuan.swan.cloud.oauth2.DefaultOAuth2Helper;
import cn.jingyuan.swan.cloud.oauth2.error.DefaultWebResponseExceptionTranslator;
import cn.jingyuan.swan.uaa.oauth2.UsernameTokenGranter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;


/**
 * 授权服务器配置
 */
@Slf4j
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Resource(name = "defaultClientDetailsService")
    ClientDetailsService clientDetailsService;

    @Resource
    UserDetailsService userDetailsService;

    @Resource
    AuthenticationManager authenticationManager;

    @Resource
    TokenStore tokenStore;

    // @Resource
    // TokenEnhancer tokenEnhancer;


    @Bean
    public TokenStore tokenStore() {
        tokenStore = new InMemoryTokenStore();
        return tokenStore;
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
            .tokenKeyAccess("permitAll")
            .checkTokenAccess("permitAll()")

            .allowFormAuthenticationForClients();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetailsService);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
            .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
            //密码模式使用
            .authenticationManager(authenticationManager)
            // .approvalStore()
            // .tokenStore()
            .userDetailsService(userDetailsService)
            .tokenServices(tokenServices())
            // .authorizationCodeServices()

            .accessTokenConverter(DefaultOAuth2Helper.buildAccessTokenConverter());

        // 警告：不要移动位置
        // 新增 username 认证
        UsernameTokenGranter usernameTokenGranter =
            new UsernameTokenGranter(
                userDetailsService,
                endpoints.getTokenServices(),
                endpoints.getClientDetailsService(),
                endpoints.getOAuth2RequestFactory()
            );

        List<TokenGranter> tokenGranters = new ArrayList<>();
        tokenGranters.add(endpoints.getTokenGranter());
        tokenGranters.add(usernameTokenGranter);

        endpoints
            .tokenGranter(new CompositeTokenGranter(tokenGranters))
            .exceptionTranslator(new DefaultWebResponseExceptionTranslator())

            // 自定义确认授权页面
            .pathMapping("/oauth/confirm_access", "/oauth/confirm_access")

            // 自定义错误页
            .pathMapping("/oauth/error", "/oauth/error")
        ;
    }

    private DefaultTokenServices tokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(tokenStore);
        // token 增强
        // tokenServices.setTokenEnhancer(tokenEnhancer);
        tokenServices.setSupportRefreshToken(true);
        // https://echocow.cn/articles/2020/01/20/1579503807596.html
        // 该字段设置设置 refresh token 是否重复使用，true:reuse；false:no reuse.
        tokenServices.setReuseRefreshToken(true);
        tokenServices.setClientDetailsService(clientDetailsService);

        return tokenServices;
    }

}
